#include "eightlayerim.h"
#include "freefuncs.h"
#include <assert.h>
#include <sstream>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>

EightLayerIM::EightLayerIM(ImageMatrix imageArray[], int validImages) : validImages(validImages)
{
	for (int i = 0; i < validImages; i++)
		this->image[i] = imageArray[i];
}

EightLayerIM::EightLayerIM (string baseName, int layersNum, string type)
{
	assert (layersNum < 9 && layersNum > 0 && "Error: invalid start and end value for loading the sequence of images.");
	assert ( (type == "bmp" || type == "txt") && "invalid file type provided for creating an EightLayerIM object. "
		&& "valid types are only txt and bmp, all lowercase.");
	this->validImages = layersNum;
	if (type == "txts")
	{
#ifdef COMMENTS_ON
		cout << "Creating an EightLayerIM object from a set of text files.\n";
#endif
		//char myBuff[2];
		for (int i = 0; i < layersNum; i++)
			this->image[i] = ImageMatrix(baseName+"_bit" + int2Str(i) /*_itoa(i,myBuff,10)*/ + ".txt");
	}

	else if (type == "txt")
	{
#ifdef COMMENTS_ON
		cout << "Creating an EightLayerIM object from a single text file.\n";
#endif
		int pValue;
		int tempMatrices[8][MROWS][MCOLS];
		string fileName(baseName + ".txt");
		ifstream inputTextFile(fileName.data());
		if (inputTextFile.is_open())
		{
			for (int r = 0; r < MROWS ; r++)
				for (int c = 0; c < MCOLS; c++)
				{
					inputTextFile >> pValue;
					for (int l = 0; l < layersNum; l++)
					{						
						if (pValue >= (int) pow((double)2, layersNum-1-l)) //is the bit for this layer "1"?
						{
							tempMatrices[l][r][c] = 0;
							pValue -= (int)pow((double)2,layersNum-1-l);
						}
						else
							tempMatrices[l][r][c] = 1;
					}
				}

		for (int l = 0; l < layersNum; l++)
			this->image[l].load(tempMatrices[l]);
		}
		else
			cout << "Inputfile " << baseName << " cannot be opened.\n";					
	}

	else if (type == "bmp")
	{
#ifdef COMMENTS_ON
		cout << "Creating an EightLayerIM object from a bitmap image\n";
#endif
		CBitmap inputImage(baseName + ".bmp");
		int pValue;
		int tempMatrices[8][MROWS][MCOLS];
		for (int r = 0; r < MROWS ; r++)
			for (int c = 0; c < MCOLS; c++)
			{
				pValue = inputImage.getIntensity(r, c);
				for (int l = 0; l < layersNum; l++)
				{						
					//if (pValue >= (int) pow((double)2, layersNum-1-l)) //is the bit for this layer "1"? //EDIT: I fix it so the firs layer (ImageMatrix[0]) is the most significant bit.
					if (pValue >= (int) pow((double)2, BITS_PER_PIXEL-1-l)) //is the bit for this layer "1"?
					{
						tempMatrices[l][r][c] = 0;
						//pValue -= (int)pow((double)2,layersNum-1-l);//EDIT: I fix it so the firs layer (ImageMatrix[0]) is the most significant bit.
						pValue -= (int)pow((double)2, BITS_PER_PIXEL-1-l);
					}
					else
						tempMatrices[l][r][c] = 1;
				}
			}

		for (int l = 0; l < layersNum; l++)
			this->image[l].load(tempMatrices[l]);
	}

}

void EightLayerIM::copyImagesTo(ImageMatrix images[], int size) const
{
	assert (size==8 && "Error: Copying the content of EightLayerIM to an array of ImageMatrix whose size is not 8.");
	for (int i = 0; i < this->validImages ; i++)
		images[i] = this->image[i];

	for (int i = this->validImages; i < 8; i++)
		images[i].clean();
}

//void EightLayerIM::updateLongInstance(int row, int col, int ifSize, LongInstance& targetLI) const
//{
//	assert ((ifSize < this->validImages) && (ifSize > 0) && "There is not this many bits to be used");
//	targetLI.clear();
//	for (int n = 0; n < ifSize; n++)
//		targetLI.addPhase(this->image[n], row, col, this->image[n+1].getValue(row,col));
//}

void EightLayerIM::addImageMatrix (const ImageMatrix& im)
{
	assert (this->validImages < 8 && "Error: Adding an image to an eightlayerIM that is already full.");
	//this->validImages++;
	this->image[this->validImages] = im;
	this->validImages++;
}


void EightLayerIM::printLayer (int layerNum) const 
{
	assert(layerNum < this->validImages && layerNum >= 0 && "Error: Invalid Layer num to print."); 
	cout << "\nPrinting the data in Layer " << layerNum << " of " << this->validImages << ".\n";
	this->image[layerNum].printData();
}

bool EightLayerIM::flattenLayersToTextFile(string targetFileName, int layers) const
{
	if (layers == -1)
		layers = this->validImages;
	if (layers < 0 || layers > 8)
	{
		cerr << "invalid layers parameter to make the text file from the ELIM\n";
		assert (layers >= 0 && layers <= 8);
		return false;
	}
	ofstream outputFile(targetFileName.data());
	int** pixel = new int*[this->getRowNum()];
	for (int row = 0; row < getRowNum(); ++row)
	{
		pixel[row] = new int[getColNum()];
		for (int col = 0; col < getColNum(); ++col)
			pixel[row][col] = 0;
	}

	for (int layer = 0; layer < layers; ++layer)
		for (int row = 0; row < getRowNum(); ++row)
			for (int col = 0; col < getColNum(); ++col)
				pixel[row][col] += intPosPow(2,7-layer) * (1-this->image[layer].getValue(row,col));


	for (int row = 0; row < getRowNum(); ++row)
	{
		for (int col = 0; col < getColNum(); ++col)
			outputFile << pixel[row][col] << "\t";
		outputFile << endl;
	}
	return true;
}

bool EightLayerIM::saveToBlankBMP(string fileName, int layers) const
{
	string textFile = "ItIsSafeToDeleteThis.txt";
	bool result = flattenLayersToTextFile(textFile, layers);
	txt2bmp(textFile, fileName);
	return result;
}

void EightLayerIM::writeToBinaryTextFiles (const string baseName, const int layers) const
{
	assert (layers > 0 && layers <= BITS_PER_PIXEL);
	for (int i = 0; i < layers; ++i)
	{
		string thisName(baseName + int2Str(i) + ".txt");
		this->image[i].saveToTXT(thisName);
	}
}

EightLayerIM& EightLayerIM::operator= (const EightLayerIM& other)
{
	if (&other == this)
		return *this;
	validImages = other.validImages;
	for (int i = 0; i < validImages; ++i)
		image[i] = other.image[i];
	return *this;
}

EightLayerIM::EightLayerIM (const EightLayerIM& other): validImages(other.validImages)
{
	for (int i = 0; i < validImages; ++i)
		image[i] = other.image[i];
}

//void EightLayerIM::fillNeighborhood2Vector(int row, int col, int firstLayer, int lastLayer, vector<Neighborhood2>& target, int radius) const
//{
//	assert(	firstLayer >= 0 && 
//			lastLayer >= firstLayer && 
//			lastLayer < validImages && 
//			row < this->getRowNum() && 
//			col < this->getColNum() && 
//			target.size() ==0);
//
//	Neighborhood2 toBeAdded;
//	for (int historyStep = firstLayer; historyStep <= lastLayer; ++historyStep)
//	{
//		toBeAdded.updateFromImageMatrix(getImage(historyStep), row, col, radius);
//		target.push_back(toBeAdded);
//	}
//}
//
//void EightLayerIM::fillNeighborhoodVector(int row, int col, int firstLayer, int lastLayer, vector<Neighborhood>& target) const
//{
//		assert(	firstLayer >= 0 && 
//			lastLayer >= firstLayer && 
//			lastLayer < validImages && 
//			row < this->getRowNum() && 
//			col < this->getColNum() && 
//			target.size() ==0);
//
//	Neighborhood toBeAdded;
//	for (int historyStep = firstLayer; historyStep <= lastLayer; ++historyStep)
//	{
//		toBeAdded.updateFromImageMatrix(getImage(historyStep), row, col);
//		target.push_back(toBeAdded);
//	}
//}